/**
 * Ingenius-Group S.A.S
 *
 * Project: SAU
 * File: CoreServiceImpl.java
 * Date: 01/03/2011
 */

package com.ingenius.sau.server.service;

import java.util.ArrayList;
import java.util.List;

import com.extjs.gxt.ui.client.data.BasePagingLoadConfig;
import com.extjs.gxt.ui.client.data.PagingLoadResult;
import com.ingenius.sau.client.service.CoreService;
import com.ingenius.sau.server.persistence.AcademicProgramDAO;
import com.ingenius.sau.server.persistence.AssignedInstrumentDAO;
import com.ingenius.sau.server.persistence.DAOFactory;
import com.ingenius.sau.server.persistence.Factor2EvaluateDAO;
import com.ingenius.sau.server.persistence.Feature2EvaluateDAO;
import com.ingenius.sau.server.persistence.Indicator2EvaluateDAO;
import com.ingenius.sau.server.persistence.ScaleDAO;
import com.ingenius.sau.server.persistence.SelfEvaluationDAO;
import com.ingenius.sau.server.persistence.jdo.JdoDAOFactory;
import com.ingenius.sau.shared.model.core.Factor2Evaluate;
import com.ingenius.sau.shared.model.core.Feature2Evaluate;
import com.ingenius.sau.shared.model.core.Indicator2Evaluate;
import com.ingenius.sau.shared.model.core.Scale;
import com.ingenius.sau.shared.model.core.SelfEvaluation;
import com.ingenius.sau.shared.model.guidelines.Factor;
import com.ingenius.sau.shared.model.guidelines.Feature;
import com.ingenius.sau.shared.model.guidelines.Guideline;
import com.ingenius.sau.shared.model.guidelines.Indicator;
import com.ingenius.sau.shared.model.instruments.AssignedInstrument;
import com.ingenius.sau.shared.model.instruments.Document;
import com.ingenius.sau.shared.model.instruments.Question;
import com.ingenius.sau.shared.model.programs.AcademicProgram;
import com.ingenius.sau.shared.model.users.Group;
import com.ingenius.sau.shared.util.filter.BeanFilter;
import com.ingenius.sau.shared.util.filter.Comparison;
import com.ingenius.sau.shared.util.filter.Filter;

/**
 * Class <strong>CoreServiceImpl</strong>
 * 
 * @author Jesus David
 * @version 0.1
 */
@SuppressWarnings("serial")
public class CoreServiceImpl extends AbstractService implements CoreService {

	private DAOFactory daoFactory;
	private AcademicProgramDAO academicProgramDAO;
	private SelfEvaluationDAO selfEvaluationDAO;
	private Factor2EvaluateDAO factor2EvaluateDAO;
	private Feature2EvaluateDAO feature2EvaluateDAO;
	private Indicator2EvaluateDAO indicator2EvaluateDAO;
	private AssignedInstrumentDAO assignedInstrumentDAO;
	private ScaleDAO scaleDAO;

	private GuidelinesServiceImpl guidelinesService;
	private InstrumentsServiceImpl instrumentsService;
	private UsersServiceImpl usersService;

	private String currentProcessId;

	public CoreServiceImpl() {
		guidelinesService = new GuidelinesServiceImpl();
		instrumentsService = new InstrumentsServiceImpl();
		usersService = new UsersServiceImpl();

		daoFactory = JdoDAOFactory.getInstance();
		academicProgramDAO = daoFactory.createAcademicProgram();
		selfEvaluationDAO = daoFactory.createSelfEvaluationDAO();
		factor2EvaluateDAO = daoFactory.createFactor2EvaluateDAO();
		feature2EvaluateDAO = daoFactory.createFeature2EvaluateDAO();
		indicator2EvaluateDAO = daoFactory.createIndicator2EvaluateDAO();
		assignedInstrumentDAO = daoFactory.createAssignedInstrumentDAO();
		scaleDAO = daoFactory.createScaleDAO();

		createScales();
	}

	private void createScales() {
		int count = scaleDAO.count(null);

		if (count == 0) {
			Scale scale = new Scale();
			scale.setMin(0);
			scale.setMax(5);
			scale.setPassingScore(3);
			scaleDAO.save(scale);

			scale = new Scale();
			scale.setMin(0);
			scale.setMax(10);
			scale.setPassingScore(6);
			scaleDAO.save(scale);

			scale = new Scale();
			scale.setMin(0);
			scale.setMax(100);
			scale.setPassingScore(60);
			scaleDAO.save(scale);
		}
	}

	private SelfEvaluation generateItems2Evaluate(SelfEvaluation evaluation) {
		String guidelineId = evaluation.getGuidelineId();
		List<Filter> filters = new ArrayList<Filter>();
		filters.add(new BeanFilter(Comparison.EQUALS, "guideline",
				new Guideline(guidelineId)));
		List<Factor> factors = guidelinesService.findFactors(filters, null)
				.getData();

		for (Factor factor : factors) {
			Factor2Evaluate factor2Evaluate = new Factor2Evaluate();
			factor2Evaluate.setWeighing(1);
			factor2Evaluate.setName(factor.getName());
			factor2Evaluate.setDescription(factor.getDescription());
			filters.clear();
			filters.add(new BeanFilter(Comparison.EQUALS, "factor", new Factor(
					factor.getId())));
			List<Feature> features = guidelinesService.findFeatures(filters,
					null).getData();
			for (Feature feature : features) {
				Feature2Evaluate feature2Evaluate = new Feature2Evaluate();
				feature2Evaluate.setWeighing(1);
				feature2Evaluate.setName(feature.getName());
				feature2Evaluate.setDescription(feature.getDescription());
				feature2Evaluate.setAspects2Evaluate(feature
						.getAspects2Evaluate());
				filters.clear();
				filters.add(new BeanFilter(Comparison.EQUALS, "feature",
						new Feature(feature.getId())));
				List<Indicator> indicators = guidelinesService.findIndicators(
						filters, null).getData();
				for (Indicator indicator : indicators) {
					Indicator2Evaluate indicator2Evaluate = new Indicator2Evaluate();
					indicator2Evaluate.setWeighing(1);
					indicator2Evaluate.setName(indicator.getName());
					indicator2Evaluate.setDescription(indicator
							.getDescription());
					feature2Evaluate.addIndicator2Evaluate(indicator2Evaluate);
				}
				factor2Evaluate.addFeature2Evaluate(feature2Evaluate);
			}
			evaluation.addFactor2Evaluate(factor2Evaluate);
		}
		return evaluation;
	}

	private void calculateGrades() {
		if (currentProcessId != null && !currentProcessId.isEmpty()) {
			try {
				float gradeIndicator, gradeFeature, gradeFactor, gradeProcess;
				float weighingsIndicators, weighingsFeatures, weighingsFactors;

				List<Filter> filters = new ArrayList<Filter>();
				filters.add(new BeanFilter(Comparison.EQUALS, "process",
						new SelfEvaluation(currentProcessId)));
				List<Factor2Evaluate> factors = findFactors2Evaluate(filters,
						null).getData();
				gradeProcess = weighingsFactors = 0;
				for (Factor2Evaluate factor : factors) {

					filters.clear();
					filters.add(new BeanFilter(Comparison.EQUALS,
							"factor2Evaluate", new Factor2Evaluate(factor
									.getId())));
					List<Feature2Evaluate> features = findFeatures2Evaluate(
							filters, null).getData();
					gradeFactor = weighingsFeatures = 0;
					for (Feature2Evaluate feature : features) {

						filters.clear();
						filters.add(new BeanFilter(Comparison.EQUALS,
								"feature2Evaluate", new Feature2Evaluate(
										feature.getId())));
						List<Indicator2Evaluate> indicators = findIndicators2Evaluate(
								filters, null).getData();
						gradeFeature = weighingsIndicators = 0;
						for (Indicator2Evaluate indicator : indicators) {
							filters.clear();
							filters.add(new BeanFilter(Comparison.EQUALS,
									"indicator2Evaluate",
									new Indicator2Evaluate(indicator.getId())));
							List<AssignedInstrument> instruments = findAssignedInstruments(
									filters, null).getData();
							gradeIndicator = 0;
							for (AssignedInstrument instrument : instruments) {
								gradeIndicator += instrument.getScore();
							}
							indicator.setGrade(gradeIndicator
									/ instruments.size());
							saveOrUpdateIndicator2Evaluate(indicator);
							gradeFeature += gradeIndicator
									* indicator.getWeighing();
							weighingsIndicators += indicator.getWeighing();
						}
						feature.setGrade(gradeFeature / weighingsIndicators);
						saveOrUpdateFeature2Evaluate(feature);
						gradeFactor += gradeFeature * feature.getWeighing();
						weighingsFeatures += feature.getWeighing();
					}
					factor.setGrade(gradeFactor / weighingsFeatures);
					saveOrUpdateFactor2Evaluate(factor);
					gradeProcess += gradeFactor * factor.getWeighing();
					weighingsFactors += factor.getWeighing();
				}
				SelfEvaluation process = getSelfEvaluation(currentProcessId);
				process.setGrade(gradeProcess / weighingsFactors);
				saveOrUpdateSelfEvaluation(process);

			} catch (Exception e) {
				System.out.println("Failed to calculate grades. "
						+ e.getMessage());
			}
		} else {
			System.out.println("No current process exist...");
		}
	}

	@Override
	public Boolean saveOrUpdateAcademicProgram(AcademicProgram program) {
		if (program.getId() == null) {
			return academicProgramDAO.save(program);
		}
		return academicProgramDAO.update(program);
	}

	@Override
	public Boolean deleteAcademicProgram(String id) {
		return academicProgramDAO.delete(id);
	}

	@Override
	public AcademicProgram getAcademicProgram(String id) {
		return academicProgramDAO.get(id);
	}

	@Override
	public PagingLoadResult<AcademicProgram> findAcademicPrograms(
			List<Filter> filters, BasePagingLoadConfig config) {

		return super.find(academicProgramDAO, filters, config);
	}

	@Override
	public Boolean saveOrUpdateSelfEvaluation(SelfEvaluation evaluation) {
		if (evaluation.getId() == null) {
			evaluation = generateItems2Evaluate(evaluation);
			return selfEvaluationDAO.save(evaluation);
		}
		return selfEvaluationDAO.update(evaluation);
	}

	@Override
	public Boolean deleteSelfEvaluation(String id) {
		return selfEvaluationDAO.delete(id);
	}

	@Override
	public SelfEvaluation getSelfEvaluation(String id) {
		return selfEvaluationDAO.get(id);
	}

	@Override
	public PagingLoadResult<SelfEvaluation> findSelfEvaluations(
			List<Filter> filters, BasePagingLoadConfig config) {

		return super.find(selfEvaluationDAO, filters, config);
	}

	@Override
	public Boolean saveOrUpdateFactor2Evaluate(Factor2Evaluate factor2Evaluate) {
		if (factor2Evaluate.getId() == null) {
			factor2EvaluateDAO.save(factor2Evaluate);
		}
		return factor2EvaluateDAO.update(factor2Evaluate);
	}

	@Override
	public Boolean deleteFactor2Evaluate(String id) {
		return factor2EvaluateDAO.delete(id);
	}

	@Override
	public Factor2Evaluate getFactor2Evaluate(String id) {
		return factor2EvaluateDAO.get(id);
	}

	@Override
	public PagingLoadResult<Factor2Evaluate> findFactors2Evaluate(
			List<Filter> filters, BasePagingLoadConfig config) {

		return super.find(factor2EvaluateDAO, filters, config);
	}

	@Override
	public Boolean saveOrUpdateFeature2Evaluate(
			Feature2Evaluate feature2Evaluate) {

		if (feature2Evaluate.getId() == null) {
			return feature2EvaluateDAO.save(feature2Evaluate);
		}
		return feature2EvaluateDAO.update(feature2Evaluate);
	}

	@Override
	public Boolean deleteFeature2Evaluate(String id) {
		return feature2EvaluateDAO.delete(id);
	}

	@Override
	public Feature2Evaluate getFeature2Evaluate(String id) {
		return feature2EvaluateDAO.get(id);
	}

	@Override
	public PagingLoadResult<Feature2Evaluate> findFeatures2Evaluate(
			List<Filter> filters, BasePagingLoadConfig config) {

		return super.find(feature2EvaluateDAO, filters, config);
	}

	@Override
	public Boolean saveOrUpdateIndicator2Evaluate(
			Indicator2Evaluate indicator2Evaluate) {

		if (indicator2Evaluate.getId() == null) {
			return indicator2EvaluateDAO.save(indicator2Evaluate);
		}
		return indicator2EvaluateDAO.update(indicator2Evaluate);
	}

	@Override
	public Boolean deleteIndicator2Evaluate(String id) {
		return indicator2EvaluateDAO.delete(id);
	}

	@Override
	public Indicator2Evaluate getIndicator2Evaluate(String id) {
		return indicator2EvaluateDAO.get(id);
	}

	@Override
	public PagingLoadResult<Indicator2Evaluate> findIndicators2Evaluate(
			List<Filter> filters, BasePagingLoadConfig config) {

		return super.find(indicator2EvaluateDAO, filters, config);
	}

	@Override
	public Boolean saveOrUpdateAssignedInstrument(
			AssignedInstrument assignedInstrument) {

		if (assignedInstrument.getId() == null) {
			boolean result = assignedInstrumentDAO.save(assignedInstrument);
			calculateGrades();
			return result;
		}
		boolean result = assignedInstrumentDAO.update(assignedInstrument);
		calculateGrades();
		return result;
	}

	@Override
	public Boolean deleteAssignedInstrument(String id) {
		boolean result = assignedInstrumentDAO.delete(id);
		calculateGrades();
		return result;
	}

	@Override
	public AssignedInstrument getAssignedInstrument(String id) {
		return assignedInstrumentDAO.get(id);
	}

	@Override
	public PagingLoadResult<AssignedInstrument> findAssignedInstruments(
			List<Filter> filters, BasePagingLoadConfig config) {

		return super.find(assignedInstrumentDAO, filters, config);
	}

	@Override
	public List<Guideline> loadAllGuidelines() {
		return guidelinesService.findGuidelines(null, null).getData();
	}

	@Override
	public List<AcademicProgram> loadAllPrograms() {
		return super.find(academicProgramDAO, null, null).getData();
	}

	@Override
	public List<Scale> loadAllScales() {
		return super.find(scaleDAO, null, null).getData();
	}

	@Override
	public List<Group> loadAllGroups() {
		return usersService.findGroups(null, null).getData();
	}

	@Override
	public List<Document> loadAllDocs() {
		return instrumentsService.findDocuments(null, null).getData();
	}

	@Override
	public List<Question> loadAllQuestions() {
		return instrumentsService.findQuestions(null, null).getData();
	}

	@Override
	public Scale getSelfEvaluationScale(String processId) {
		currentProcessId = processId;
		String scaleId = selfEvaluationDAO.get(processId).getScaleId();
		if (scaleId != null) {
			return scaleDAO.get(scaleId);
		}
		return null;
	}

}
